package org.aeon.utils;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author: MissingAeon
 * @date: 2024/1/26 14:03
 * @description: 文件IO工具类
 */
@Slf4j
public class FileIoUtil {

    /**
     * 文件读取
     *
     * @param filePath
     * @param clazz
     * @param <T>
     * @return list
     */
    public static <T> List<T> read(String filePath, Class<T> clazz) {
        Path path = Paths.get(filePath);
        try {
            if (!Files.exists(path)) {
                // 创建父文件夹及文件
                Files.createDirectories(path.getParent());
                Files.createFile(path);
                return new ArrayList<>();
            }
        } catch (IOException e) {
            log.debug("文件创建失败！");
            return new ArrayList<>();
        }
        try (final InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath))) {
            char[] buffer = new char[1024 * 1024];
            int len;
            final StringBuilder sb = new StringBuilder();
            while (((len = isr.read(buffer)) != -1)) {
                final String str = String.valueOf(buffer, 0, len);
                sb.append(str);
            }
            log.debug("文件读取成功！");
            return JsonUtils.fromJsonArray(sb.toString(), clazz);
        } catch (IOException e) {
            log.debug("文件读取失败！");
            log.error(e.getMessage(), e);
        }
        return new ArrayList<>();
    }

    /**
     * 文件写入
     *
     * @param filePath
     * @param t
     * @param <T>
     * @return
     */
    public static <T> boolean write(String filePath, List<T> t) {
        Path path = Paths.get(filePath);
        try {
            if (!Files.exists(path)) {
                // 创建父文件夹及文件
                Files.createDirectories(path.getParent());
                Files.createFile(path);
            }
        } catch (IOException e) {
            log.debug("文件创建失败！");
            return false;
        }
        try (final OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath))) {
            final String json = new Gson().toJson(t);
            osw.write(json);
            log.debug("文件写入成功");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            log.debug("文件写入失败");
        }
        return false;
    }

    /**
     * JSON文件写入追加
     *
     * @param filePath
     * @param t
     * @param <T>
     * @return
     */
    public static <T> boolean jsonWriteTail(String filePath, List<T> t) {
        final long length;
        // 没有文件或者文件为空就转到普通写入
        if (!Files.exists(Paths.get(filePath)) || (length = fileLength(filePath)) == 0) {
            return write(filePath, t);
        }
        // 创建随机访问文件 “rw“
        try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
            // 移动文件指针到特定位置 ，seek 的参数是字节偏移量，从文件的开头开始计算
            raf.seek(length - 2);
            final String json = new Gson().toJson(t);
            raf.write((", " + json.substring(1)).getBytes());
            log.debug("文件追加成功");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            log.debug("文件追加失败");
        }
        return false;
    }


    /**
     * JSON文件写入追加
     *
     * @param filePath
     * @param t
     * @param <T>
     * @return
     */
    public static <T> boolean jsonWriteTail(String filePath, T t) {
        final long length;
        // 没有文件或者文件为空就转到普通写入
        if (!Files.exists(Paths.get(filePath)) || (length = fileLength(filePath)) == 0) {
            return write(filePath, Collections.singletonList(t));
        }
        // 创建随机访问文件 “rw“
        try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
            pointerCorrection(length, raf);
            final String json = new Gson().toJson(t);
            raf.write((", " + json + "]").getBytes());
            log.debug("文件追加成功");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            log.debug("文件追加失败");
        }
        return false;
    }

    /**
     * 修正指针让刚好覆盖
     *
     * @param length
     * @param raf
     * @throws IOException
     */
    private static void pointerCorrection(long length, RandomAccessFile raf) throws IOException {
        // 移动文件指针到特定位置 ，seek 的参数是字节偏移量，从文件的开头开始计算
        raf.seek(length - 1);
        while (raf.read() != ']') {
            raf.seek(raf.getFilePointer() - 2);
            if (raf.getFilePointer() == 0) {
                throw new IOException("无法识别结束符号");
            }
        }
        raf.seek(raf.getFilePointer() - 1);
    }

    /**
     * 获取文件的字节长度
     *
     * @param filePath
     * @return
     */
    public static long fileLength(String filePath) {
        final File file = new File(filePath);
        return file.exists() ? file.length() : 0;
    }
}
